﻿using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.ComponentModel;
using System.Transactions;
using System.Data.SqlClient;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data.Common;
using System.Text;

namespace ITOMMS.Entity
{
    /// <summary>
    /// 所有实体类的基类,提供了持久化的操作
    /// //支持撤消,支持操作数据库
    /// </summary>
    [Serializable]
    public abstract class BaseEntity<T, Tid> : INotifyPropertyChanged
    {
        #region DAO

        /// <summary>
        /// 返回对应主键的实体
        /// </summary>
        /// <param name="id">主键</param>
        /// <param name="shouldLock">true false都行,已经没有实际意义</param>
        /// <returns>对应主键的实体</returns>
        public virtual T GetById(Tid id)
        {
            throw new Exception("请调用子类的方法:GetById(IdT id)");
        }

        //public TransactionScope GetTranster()
        //{
        //    TransactionScope ts = new TransactionScope();
        //    return ts;
        //}

        public void StartTrans(TransactionScope ts)
        {

        }


        /// <summary>
        /// 查找一行记录(如果没有结果则返回为null)
        /// </summary>
        /// <param name="strSql">没有where 的SQL条件,如: name = 'abc' </param>
        /// <returns>返回查询到结果的第一行记录</returns>
        public T FindEntity(string strSql)
        {
            List<T> list = GetAllByQuery(strSql);
            if (list.Count > 0)
            {
                T entity = list[0];
                return entity;
            }
            return default(T);
        }

        /// <summary>
        /// 从数据库中返回所有表的对象集合
        /// </summary>
        public abstract List<T> GetAll();

        /// <summary>
        /// 从数据库中返回所有表的对象集合行数
        /// </summary>
        public abstract int GetTotalRecords();


        /// <summary>
        /// 从数据库中返回所有表的对象集合行数
        /// </summary>
        /// <param name="sqlCondition">条件</param>
        public abstract int GetTotalRecords(string sqlCondition);

        /// <summary>
        /// 新增实体
        /// 不支持事务，不能回滚
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns>新增的实体对象</returns>
        public virtual int Save()
        {
            throw new Exception("请调用子类的方法:Save(T entity)");
        }


        /// <summary>
        /// 新增实体
        /// 不支持事务，不能回滚
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns>新增的实体对象</returns>
        public virtual int Save(T entity)
        {
            throw new Exception("请调用子类的方法:Save(T entity)");
        }


        /// <summary>
        /// 保存存者更新一个实体(实际上也是调用了Save 和Update方法
        /// 如果传入的实体主键不存在同新增,否则更新
        /// </summary>
        /// <param name="entity">要操作的实体对象</param>
        /// <returns>返回影响的行数</returns>
        public virtual int SaveOrUpdate(T entity)
        {
            throw new Exception("请调用子类的方法:SaveOrUpdate(T entity)");
        }

        /// <summary>
        /// 保存存者更新一个实体(实际上也是调用了Save 和Update方法
        /// 如果传入的实体主键不存在同新增,否则更新
        /// </summary>
        /// <param name="entity">要操作的实体对象</param>
        /// <returns>返回影响的行数</returns>
        public virtual int SaveOrUpdate()
        {
            throw new Exception("请调用子类的方法:SaveOrUpdate(T entity)");
        }


        /// <summary>
        /// 不支持事务，修改后就Commit，不能回滚
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <param name="ID">实体对象的ID</param>
        /// <returns></returns>
        public virtual int Update(T entity)
        {
            throw new Exception("请调用子类的方法:Update(T entity)");
        }


        /// <summary>
        /// 不支持事务，修改后就Commit，不能回滚
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <param name="ID">实体对象的ID</param>
        /// <returns></returns>
        public virtual int Update()
        {
            throw new Exception("请调用子类的方法:Update(T entity)");
        }

        /// <summary>
        /// Delete Records,只能删除一条记录
        /// </summary>
        /// <param name="entity">被删除主键ID</param>
        public virtual int Delete(Tid id)
        {
            throw new Exception("请调用子类的方法:Delete()");
        }

        /// <summary>
        /// Delete Records,只能删除一条记录
        /// </summary>
        /// <param name="entity">被删除主键ID</param>
        public virtual int Delete(T entity)
        {
            throw new Exception("请调用子类的方法:Delete(T entity)");
        }


        /// <summary>
        /// 条件删除，支持批量删除,子类中不能 new or override
        /// 传入原始的sql语句: delete from XXX where ID=XX
        /// </summary>
        /// <param name="strSQL"></param>
        public int Delete(string strSQL)
        {

            StringBuilder strSql = new StringBuilder();
            strSql.Append(strSQL);
            Database db = GetDatabase();
            DbCommand dbCommand = db.GetSqlStringCommand(strSql.ToString());
            return db.ExecuteNonQuery(dbCommand);

        }


        /// <summary>
        /// 通过主键查询,检测对应的实体是否存在于数据库当中
        /// </summary>
        /// <param name="ID">主键</param>
        /// <returns></returns>
        public virtual bool IsExist(Tid id)
        {
            throw new Exception("请调用子类的方法:IsExist(IdT ID)");
        }


        /// <summary>
        /// 返回符合条件的实体集合
        /// </summary>
        /// <param name="strSql">没有where条件的sql条件语句,如: name = 'abc'</param>
        /// <returns>符合条件的实体集合</returns>
        public abstract List<T> GetAllByQuery(string strSql);

        public abstract List<T> GetAllByQuery(string strSql, List<IDataParameter> parameters);

        public abstract List<T> GetAllByQuery(string strSql, int rowNumber);

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="strSql">查询条件</param>
        /// <param name="PageSize">每页记录数</param>
        /// <param name="CurrentPageIndex">当前页</param>
        /// <returns></returns>
        public abstract List<T> GetAllByQuery(string strSql, int PageSize, int CurrentPageIndex);


        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="strSql">查询条件</param>
        /// <param name="PageSize">每页记录数</param>
        /// <param name="CurrentPageIndex">当前页</param>
        /// <param name="strSort">ex:order by id desc </param>
        /// <returns></returns>
        public abstract List<T> GetAllByQuery(string strSql,string strSort, int PageSize, int CurrentPageIndex);


        public abstract List<T> GetAllByQuery(string strSql, List<IDataParameter> parameters, int rowNumber);


        /// <summary>
        /// sql更新，支持批量更新
        /// </summary>
        /// <param name="strSQL">更新的strSQL语句</param>
        /// <returns></returns>
        public int Update(string strSQL)
        {
            StringBuilder strSql = new StringBuilder();
            strSql.Append(strSQL);
            Database db = GetDatabase();
            DbCommand dbCommand = db.GetSqlStringCommand(strSql.ToString());
            return db.ExecuteNonQuery(dbCommand);
        }




        public virtual bool CheckEntityValue(T Entity)
        {
            return false;
        }

        /// <summary>
        /// 执行一个SQL语句返回一个DATASET
        /// </summary>
        /// <param name="sqlstr">SQL语句</param>
        /// <returns>返回表名为Table1数据集</returns>
        public DataSet GetDataSet(String strWhere)
        {
            strWhere = SQLInjectionFilter(strWhere);
            DataSet ds = new DataSet();
            try
            {
                Database db = GetDatabase();
                DbCommand cmd = db.GetSqlStringCommand(strWhere);
                ds = db.ExecuteDataSet(cmd);
                //DbDataAdapter adapter = db.GetDataAdapter();
                //adapter.SelectCommand = cmd;

                // adapter.Fill(ds, "table");

            }
            catch (Exception er)
            {
                throw er;
            }
            return ds;
        }



        /// <summary>
        /// 执行一个SQL语句返回一个DATASET
        /// </summary>
        /// <param name="sqlstr">SQL语句</param>
        /// <param name="Begin">开始下标</param>
        /// <param name="End">结束下标</param>
        /// <returns>返回表名为Table1数据集</returns>
        public DataSet GetDataSet(String strWhere, int Begin, int End)
        {
            strWhere = SQLInjectionFilter(strWhere);
            DataSet ds = new DataSet();
            try
            {
                Database db = GetDatabase();
                DbCommand cmd = db.GetSqlStringCommand(strWhere);
                DbDataAdapter adapter = db.GetDataAdapter();
                adapter.SelectCommand = cmd;

                adapter.Fill(ds, Begin, End, "table");

            }
            catch (Exception er)
            {
                throw er;
            }
            return ds;
        }


        /// <summary>
        /// 根据表名 开始下标 和结束下标 来返回数据集
        /// </summary>
        /// <param name="TableName">表名</param>
        /// <param name="Bgein">开始下标</param>
        /// <param name="End">结束下标</param>
        /// <returns>返回一个该表的数据集</returns>
        public DataSet GetDataSetForName(String TableName, int Begin, int End)
        {
            TableName = SQLInjectionFilter(TableName);
            DataSet ds = new DataSet();
            try
            {
                Database db = GetDatabase();
                String sqlstr = "select * from " + TableName;
                DbCommand cmd = db.GetSqlStringCommand(sqlstr);
                DbDataAdapter adapter = db.GetDataAdapter();
                adapter.SelectCommand = cmd;
                adapter.Fill(ds, Begin, End, TableName);

            }
            catch (Exception er)
            {
                throw er;
            }
            return ds;
        }

        #region 执行存储过程

        /// <summary>
        /// 执行存储过程，返回影响的行数		
        /// </summary>       
        public int RunProcedure(string storedProcName)
        {
            Database db = GetDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcName);
            return db.ExecuteNonQuery(dbCommand);

        }

        /// <summary>
        /// 执行存储过程，返回输出参数的值和影响的行数		
        /// </summary>
        /// <param name="storedProcName">存储过程名</param>
        /// <param name="parameters">存储过程参数</param>
        /// <param name="OutParameter">输出参数名称</param>
        /// <param name="rowsAffected">影响的行数</param>
        /// <returns></returns>
        public object RunProcedure(string storedProcName, IDataParameter[] InParameters, SqlParameter OutParameter, out int rowsAffected)
        {
            Database db = GetDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcName);
            BuildDBParameter(db, dbCommand, (SqlParameter[])InParameters);
            db.AddOutParameter(dbCommand, OutParameter.ParameterName, OutParameter.DbType, OutParameter.Size);
            rowsAffected = db.ExecuteNonQuery(dbCommand);
            return db.GetParameterValue(dbCommand, "@" + OutParameter.ParameterName);

        }


        /// <summary>
        /// 执行存储过程，返回SqlDataReader ( 注意：使用后一定要对SqlDataReader进行Close )
        /// </summary>
        /// <param name="storedProcName">存储过程名</param>
        /// <param name="parameters">存储过程参数</param>
        /// <returns>SqlDataReader</returns>
        public SqlDataReader RunProcedure(string storedProcName, IDataParameter[] parameters)
        {
            Database db = GetDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcName);
            BuildDBParameter(db, dbCommand, parameters);
            return (SqlDataReader)db.ExecuteReader(dbCommand);

        }


        /// <summary>
        /// 执行存储过程，返回DataSet
        /// </summary>
        /// <param name="storedProcName">存储过程名</param>
        /// <param name="parameters">存储过程参数</param>
        /// <param name="tableName">DataSet结果中的表名</param>
        /// <returns>DataSet</returns>
        public DataSet RunProcedure(string storedProcName, IDataParameter[] parameters, string tableName)
        {
            Database db = GetDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcName);
            BuildDBParameter(db, dbCommand, parameters);
            return db.ExecuteDataSet(dbCommand);

        }


        /// <summary>
        /// 执行存储过程，返回DataSet(设定等待时间)
        /// </summary>
        public DataSet RunProcedure(string storedProcName, IDataParameter[] parameters, string tableName, int Times)
        {
            Database db = GetDatabase();
            DbCommand dbCommand = db.GetStoredProcCommand(storedProcName);
            dbCommand.CommandTimeout = Times;
            BuildDBParameter(db, dbCommand, parameters);
            return db.ExecuteDataSet(dbCommand);

        }

        #endregion


        #region 受保护的方法

        /// <summary>
        /// 得到对应表的最大主键值
        /// </summary>
        /// <param name="columnsOfTable">表名</param>
        /// <returns></returns>
        protected int GetMax(string columnsOfTable)
        {
            int rs = 0;

            //开发阶段如果表中字段就没有就自动创建
            //实现会多操作数据库所有发布后不再判断

            System.Text.StringBuilder sbtemp = new System.Text.StringBuilder();
            sbtemp.Append("  IF not EXISTS (  ");
            sbtemp.Append("         SELECT id  ");
            sbtemp.Append("         FROM   syscolumns  ");
            sbtemp.Append("         WHERE  id = (  ");
            sbtemp.Append("                    SELECT id  ");
            sbtemp.Append("                    FROM   sysobjects  ");
            sbtemp.Append("                    WHERE  id = OBJECT_ID(N'[HILO_TBL]')  ");
            sbtemp.Append("                )  ");
            sbtemp.Append("                AND [name] = '").Append(columnsOfTable).Append("'  ");
            sbtemp.Append("     )  ");
            sbtemp.Append("    ");
            sbtemp.Append("  BEGIN  ");
            sbtemp.Append("      ALTER TABLE [HILO_TBL] ADD ").Append(columnsOfTable).Append(" INT DEFAULT 0          ");
            sbtemp.Append("  END     ");
            Database tempdb = GetDatabase();
            DbCommand tempdbCommand = tempdb.GetSqlStringCommand(sbtemp.ToString());
            tempdb.ExecuteNonQuery(tempdbCommand);



            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append("      DECLARE @Max INT   ");
            sb.Append("  BEGIN  ");
            sb.Append("      SET @Max = 0   ");
            sb.Append("      SELECT @Max = ISNULL(MAX(").Append(columnsOfTable).Append("), 0) + 1  ");
            sb.Append("      FROM   HILO_TBL ht  ");
            sb.Append("        ");
            sb.Append("      UPDATE HILO_TBL  ");
            sb.Append("      SET    ").Append(columnsOfTable).Append(" = @Max  ");
            sb.Append("  END  ");
            sb.Append(" SELECT  @Max ");
            sb.Append("    ");
            Database db = GetDatabase();
            DbCommand dbCommand = db.GetSqlStringCommand(sb.ToString());

            rs = (int)db.ExecuteScalar(dbCommand);
            return rs;


        }


        /// <summary>
        /// 加载参数
        /// </summary>
        protected static void BuildDBParameter(Database db, DbCommand dbCommand, params IDataParameter[] cmdParms)
        {
            foreach (IDataParameter sp in cmdParms)
            {
                db.AddInParameter(dbCommand, sp.ParameterName, sp.DbType, sp.Value);
            }
        }




        /// <summary>
        /// SQL注入过滤器.
        /// </summary>
        /// <param name="sql">SQL查询参数.</param>
        /// <returns>返回一个过滤后的查询参数.</returns>
        protected static string SQLInjectionFilter(string sql)
        {
            //对输入的字符串限制在小写.
            sql = sql.ToLower();

            sql = sql.Replace("/*", string.Empty);
            sql = sql.Replace("*/", string.Empty);
            // sql = sql.Replace("'", "''");
            //sql = sql.Replace("[", "[[]");
            //sql = sql.Replace("]", "[]]");
            //sql = sql.Replace("%", "[%]");
            sql = sql.Replace("--", "[--]");
            sql = sql.Replace(";", string.Empty);
            sql = sql.Replace("xp_", string.Empty);
            //sql = sql.Replace("_", "[_]");

            return sql;
        }

        /// <summary>
        /// 拼接sql连接字符串
        /// </summary>
        /// <param name="strUserID">userid</param>
        /// <param name="strUserPwd">pwd</param>
        /// <returns></returns>
        protected static string GetSQLConnectStr(string strUserID, string strUserPwd)
        {
            string strDataSource = ""; //ConfigHelper.getWebConfigAttribute("SQL_DataSource");
            string strDataBase = "";//ConfigHelper.getWebConfigAttribute("SQL_DataBase");
            string strSql = "Data Source=" + strDataSource + ";Database=" + strDataBase + ";User ID=" +
                strUserID + ";Password=" + strUserPwd + ";";
            return strSql;
        }


        /// <summary>
        /// 根据访问组及根据不同连接字符串创建对应的数据库对象
        /// </summary>
        /// <returns>SqlDatabase的实例</returns>
        protected static Database GetDatabase()
        {
            //if (SessionHelper.CMESM_Group == "CM")
            //{
            Database db = DatabaseFactory.CreateDatabase();
            return db;
            //}
            //else
            //{
            //    string strUsername = SessionHelper.CMESM_DBUserName;
            //    string strUserPwd = SessionHelper.CMESM_DBUserPwd;
            //    string strconnSql = GetSQLConnectStr(strUsername, strUserPwd);
            //    SqlDatabase db = new SqlDatabase(strconnSql);
            //    return db as Database;
            //}
        }
        #endregion


        #endregion

        #region Data Member

        bool _disablePropertyChangeEvent = false;
        Watson.Core.Validation.ValidationRules _validationRules = null;

        #endregion

        #region Properties

        #region Internal Properties

        /// <summary>
        /// get/set the Disable Property change event value
        /// </summary>
        internal bool DisablePropertyChangeEvent
        {
            get { return _disablePropertyChangeEvent; }
            set { _disablePropertyChangeEvent = value; }
        }

        /// <summary>
        /// get the list of validation rules
        /// </summary>
        [System.ComponentModel.Bindable(false), Browsable(false)]
        public Watson.Core.Validation.ValidationRules ValidationRules
        {
            get
            {
                if (_validationRules == null)
                {
                    _validationRules = new Watson.Core.Validation.ValidationRules(this);

                    // Add the validation rules for this object
                    AddValidationRules();
                }

                return _validationRules;

            }

        }

        #endregion

        #region Public Properties

        /// <summary>
        /// gets the valid status of the object
        /// </summary>
        [System.ComponentModel.Bindable(false), Browsable(false)]
        public bool IsValid
        {
            get
            {
                return this.ValidationRules.IsValid;
            }
        }

        /// <summary>
        /// get the list of the broken rules
        /// </summary>
        [System.ComponentModel.Bindable(false)]
        public Watson.Core.Validation.BrokenRulesList BrokenRulesList
        {
            get
            {
                return ValidationRules.BrokenRules;
            }
        }

        #endregion

        #endregion

        #region Virtual Methods

        /// <summary>
        /// Add validation rules
        /// </summary>
        internal virtual void AddValidationRules()
        {

        }

        #endregion

        #region Implement INotifyPropertyChanged

        /// <summary>
        /// override Property Change event of INotifyPropertyChanged
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// method called when property has changed
        /// </summary>
        /// <param name="propertyName">The name of the property that has changed.</param>
        protected virtual void PropertyHasChanged(string propertyName)
        {
            if (!DisablePropertyChangeEvent)
            {
                // call overloaded method
                PropertyHasChanged(new PropertyChangedEventArgs(propertyName));
            }
        }

        /// <summary>
        /// Called when a property has changed
        /// </summary>
        /// <param name="e">PropertyChangedEventArgs</param>
        protected virtual void PropertyHasChanged(PropertyChangedEventArgs e)
        {
            if (!DisablePropertyChangeEvent)
            {
                ValidationRules.ValidateRules(e.PropertyName);

                if (PropertyChanged != null)
                {
                    PropertyChanged(this, e);
                }
            }
        }

        #endregion
    }
}

